/***** BEGIN LICENSE BLOCK *****
Copyright the original author Andy Shaules ( bowljoman AT hotmail DOT com) thebitstream.com
Licensed under the MOZILLA PUBLIC LICENSE, Version 1.1 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
	http://www.mozilla.org/MPL/MPL-1.1.html
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

# ***** END LICENSE BLOCK *****/
package sandy.redSandy
{
	import flash.utils.Dictionary;
	import flash.utils.getTimer;
	
	import sandy.core.Scene3D;
	import sandy.core.scenegraph.TransformGroup;
	import sandy.events.SandyEvent;
	/**
	 * 
	 * @author Andy Shaules
	 * 
	 */
	public class SharedTransformGroup extends TransformGroup
	{
		public var m_nVelocityX:Number=0;
		public var m_nVelocityY:Number=0;
		public var m_nVelocityZ:Number=0;
		public var m_nRotateVelocityX:Number=0;
		public var m_nRotateVelocityY:Number=0;
		public var m_nRotateVelocityZ:Number=0;
		public var m_nAccellVelocityX:Number=0;
		public var m_nAccellVelocityY:Number=0;
		public var m_nAccellVelocityZ:Number=0;
		public var m_nAccellRotateVelocityX:Number=0;
		public var m_nAccellRotateVelocityY:Number=0;
		public var m_nAccellRotateVelocityZ:Number=0;
		
		
		public var when:Number=0;
			
		private var adjustedDelta:Number=0;
		
		private static var DELTA:Number=0;
		private static var LAST:Number=getTimer();
		private static var NOW:Number=getTimer();
		private static var REALTIME:Number=new Date().time;
		private static var GROUPS:Dictionary=new Dictionary();
		
		/**
		 * If using the velocity properties of the SharedTransformGroup, 
		 * you must call 'SharedTransformGroup.initiateRender()' before sandy.render().
		 */
		public static function initiateRender():void
		{
			LAST=NOW;
			NOW=getTimer();
			REALTIME=new Date().time;
			DELTA=NOW-LAST;
		}
		public function toObject():Object
		{
			return [name,
			x,y,z,
			rotateX,rotateY,rotateZ,
			m_nVelocityX,m_nVelocityY,m_nVelocityZ,
			m_nRotateVelocityX,m_nRotateVelocityY,m_nRotateVelocityZ,
			m_nAccellVelocityX,m_nAccellVelocityY,m_nAccellVelocityZ,
			m_nAccellRotateVelocityX,m_nAccellRotateVelocityY,m_nAccellRotateVelocityZ,
			String(when)];
		}
		public static function getSharedTransformGroup(name:String):SharedTransformGroup
		{
			return GROUPS[name];
		}
		internal static function removeSharedTransformGroup(name:String):void
		{
			GROUPS[name]=null;
		} 
		public function SharedTransformGroup(p_sName:String="")
		{
			super(p_sName);
			GROUPS[name]=this;
		}
		public override function set scene(p_oScene:Scene3D):void
		{			
			if(!p_oScene)
			{
				super.scene=p_oScene;
				return;
			}
			p_oScene.addEventListener(SandyEvent.SCENE_UPDATE,onRender);		
			super.scene=p_oScene;		
		}
		private function onRender(e:SandyEvent):void
		{
			
			if(adjustedDelta)
			{
				adjustedDelta=REALTIME-adjustedDelta;
				adjustedDelta=adjustedDelta-DELTA;
				
			}
			
			x=computeDistance(x,m_nVelocityX,m_nAccellVelocityX);
			y=computeDistance(y,m_nVelocityY,m_nAccellVelocityY);
			z=computeDistance(z,m_nVelocityZ,m_nAccellVelocityZ);			
			rotateX= r2d(computeRotation(d2r(rotateX),d2r(m_nRotateVelocityX),d2r(m_nAccellRotateVelocityX) ));
			rotateY= r2d(computeRotation(d2r(rotateY),d2r(m_nRotateVelocityY),d2r(m_nAccellRotateVelocityY) ));
			rotateZ= r2d(computeRotation(d2r(rotateZ),d2r(m_nRotateVelocityZ),d2r(m_nAccellRotateVelocityZ) ));
			

			
			m_nVelocityX=computeVelocity(m_nVelocityX,m_nAccellVelocityX);
			m_nVelocityY=computeVelocity(m_nVelocityY,m_nAccellVelocityY);
			m_nVelocityZ=computeVelocity(m_nVelocityZ,m_nAccellVelocityZ);
			m_nRotateVelocityX=computeVelocity(m_nRotateVelocityX,m_nAccellRotateVelocityX);
			m_nRotateVelocityY=computeVelocity(m_nRotateVelocityY,m_nAccellRotateVelocityY);
			m_nRotateVelocityZ=computeVelocity(m_nRotateVelocityZ,m_nAccellRotateVelocityZ);
						

			
			
			adjustedDelta=0;		
		}
		private function computeDistance(aPosition:Number,bVelocity:Number,cAccel:Number):Number
		{	
			return aPosition + (bVelocity*(DELTA+adjustedDelta)/1000)+ ( cAccel* (DELTA+adjustedDelta) /1000    * (DELTA+adjustedDelta) /1000 )/2 ;				 
		}
		private function computeRotation(aRads:Number,bVelocityRads:Number,cAccelRads:Number):Number
		{			
			return aRads + (bVelocityRads * (DELTA+adjustedDelta)/1000)+  (cAccelRads *  (DELTA+adjustedDelta) /1000    * (DELTA+adjustedDelta) /1000 )/2 ;	
		}
		private function computeVelocity(bVelocity:Number,cAccel:Number):Number
		{
			return bVelocity + (cAccel*( (DELTA+adjustedDelta) /1000  ));
		}
		private static function r2d(rads:Number):Number
		{
			return (rads*180/( 2*Math.PI))%360;
		} 
		private static function d2r(degrees:Number):Number
		{
			return degrees * 2* Math.PI/180;
		}
		public function onRedSandyPacket(obj:Object):void
		{
			
			x=obj[1];
			y=obj[2];
			z=obj[3];
			
			rotateX=obj[4];
			rotateY=obj[5];
			rotateZ=obj[6];
			
			m_nVelocityX=obj[7];
			m_nVelocityY=obj[8];
			m_nVelocityZ=obj[9];
			
			m_nRotateVelocityX=obj[10];
			m_nRotateVelocityY=obj[11];
			m_nRotateVelocityZ=obj[12];
			
			m_nAccellVelocityX=obj[13];
			m_nAccellVelocityY=obj[14];
			m_nAccellVelocityZ=obj[15];
			
			m_nAccellRotateVelocityX=obj[16];
			m_nAccellRotateVelocityY=obj[17];
			m_nAccellRotateVelocityZ=obj[18];
			
			adjustedDelta=obj[19];
			when=obj[19];
		}
		
	}
}